import {
  HttpException,
  HttpStatus,
  Inject,
  Injectable,
  Logger,
} from '@nestjs/common';
import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
import { EntityManager, In, Like, Repository } from 'typeorm';
import { LoginDto } from './dto/login.dto';
import { RegisterDto } from './dto/register.dto';
import * as crypto from 'crypto';
import { User } from './entities/user.entity';
import { Role } from './entities/role.entity';
import { Permission } from './entities/permission.entity';

// 分页
import { PaginationService } from 'src/pagination/pagination.service';
import { PaginationDto } from 'src/pagination/dto/pagination.dto';
import { CursorPaginationDto } from 'src/pagination/dto/cursorPagination.dto';

function md5(str) {
  const hash = crypto.createHash('md5');
  hash.update(str);
  console.log(hash);
  return hash.digest('hex');
}

@Injectable()
export class UserService {
  private logger = new Logger();

  @InjectRepository(User)
  private userRepository: Repository<User>;

  @InjectEntityManager()
  private entityManager: EntityManager;

  @Inject(PaginationService)
  private paginationService: PaginationService;

  async register(user: RegisterDto) {
    // 1. 首先查找用户名是否已存在
    const isExistUser = await this.userRepository.findOneBy({
      username: user.username,
    });

    if (isExistUser) {
      throw new HttpException('用户名已存在', HttpStatus.BAD_REQUEST);
    }

    // 2. 创建用户
    const newUser = new User();
    newUser.username = user.username;
    newUser.password = md5(user.password);

    // 3. 写入数据库
    try {
      await this.userRepository.save(newUser);
      return '注册成功';
    } catch (error) {
      this.logger.error(error, UserService);
      return '注册失败';
    }
  }

  async login(user: LoginDto) {
    // 1. 查找用户是否存在
    const foundUser = await this.userRepository.findOne({
      where: {
        username: user.username,
      },
      relations: {
        roles: true,
      },
    });

    if (!foundUser) {
      throw new HttpException('用户不存在', HttpStatus.BAD_REQUEST);
    }

    if (foundUser.password !== md5(user.password)) {
      throw new HttpException('密码错误', HttpStatus.BAD_REQUEST);
    }

    return foundUser;
  }

  async getUserById(userId: number) {
    // 只返回id和username
    return this.userRepository.findOne({
      where: {
        id: userId,
      },
      select: {
        id: true,
        username: true,
      },
    });
  }

  async initData() {
    const user1 = new User();
    user1.username = 'zhangsan';
    user1.password = md5('123456');

    const user2 = new User();
    user2.username = 'lisi';
    user2.password = md5('123456');

    const role1 = new Role();
    role1.name = '管理员';

    const role2 = new Role();
    role2.name = '普通用户';

    const permission1 = new Permission();
    permission1.name = '新增 aaa';

    const permission2 = new Permission();
    permission2.name = '修改 aaa';

    const permission3 = new Permission();
    permission3.name = '删除 aaa';

    const permission4 = new Permission();
    permission4.name = '查询 aaa';

    const permission5 = new Permission();
    permission5.name = '新增 bbb';

    const permission6 = new Permission();
    permission6.name = '修改 bbb';

    const permission7 = new Permission();
    permission7.name = '删除 bbb';

    const permission8 = new Permission();
    permission8.name = '查询 bbb';

    role1.permissions = [permission1, permission2, permission3, permission4];
    role2.permissions = [permission5, permission6, permission7, permission8];

    user1.roles = [role1];

    user2.roles = [role2];

    await this.entityManager.save(Permission, [
      permission1,
      permission2,
      permission3,
      permission4,
      permission5,
      permission6,
      permission7,
      permission8,
    ]);
    await this.entityManager.save(Role, [role1, role2]);
    await this.entityManager.save(User, [user1, user2]);
  }

  async findPermissionsByRoles(roleIds: number[]) {
    return this.entityManager.find(Role, {
      where: { id: In(roleIds) },
      relations: {
        permissions: true,
      },
    });
  }

  // 分页使用案例
  async allUser(paginationDto: PaginationDto) {
    const where = {};
    if (paginationDto.search) {
      where['username'] = Like(`%${paginationDto.search}%`);
    }
    return this.paginationService.pagination(
      this.userRepository,
      paginationDto,
      {
        select: ['id', 'username'],
        where,
      },
    );
  }

  // 游标分页使用案例：用法与 pagination 一样，默认指定 cursorField 为 createdAt
  // 如果需要指定 cursorField，则需要传入 cursorField 参数
  async allUserByCursor(paginationDto: CursorPaginationDto) {
    return this.paginationService.cursorPagination(
      this.userRepository,
      paginationDto,
      { select: ['id', 'username', 'createdAt'] },
    );
  }

  // 游标分页使用案例2：指定 cursorField 为 id
  // cursorField 表示拿哪个字段作为游标，cursor 表示游标的位置
  // async allUserByCursor2(paginationDto: CursorPaginationDto) {
  //   return this.paginationService.cursorPagination(
  //     this.userRepository,
  //     paginationDto,
  //     { select: ['id', 'username', 'createdAt'] },
  //     'id',
  //   );
  // }
}
